#include <intelgpumonitor.h>
#include <fstream>
#include <string>
#include <filesystem>
#include <iostream>
#include <regex>
#include <sstream>
#include <fcntl.h>  // 添加文件操作头文件
#include <unistd.h> // 添加close函数头文件

IntelGpuMonitor::~IntelGpuMonitor() = default;

IntelGpuMonitor::IntelGpuMonitor()
{
    find_intel_gpu_path();
    find_gem_objects_path();
}

void IntelGpuMonitor::find_intel_gpu_path()
{
    gpu_dev_path.clear();

    for (const auto& entry : std::filesystem::directory_iterator("/sys/class/drm"))
    {
        const std::string card_name = entry.path().filename();
        if (card_name.find("card") == 0) {

            std::string vendor_path = entry.path().string() + "/device/vendor";
            std::ifstream vendor_file(vendor_path);
            if (vendor_file.is_open())
            {
                std::string vendor_id;
                vendor_file >> vendor_id;
                if (vendor_id == "0x8086")
                {
                    gpu_dev_path = entry.path().string();
                    break;
                }
            }
        }
    }
}

void IntelGpuMonitor::find_gem_objects_path()
{
    gem_objects_path.clear();

    try {
        // 直接查找/sys/kernel/debug/dri/下的i915_gem_objects文件
        for (const auto& entry : std::filesystem::directory_iterator("/sys/kernel/debug/dri")) {
            if (entry.is_directory()) {
                std::string test_path = entry.path().string() + "/i915_gem_objects";
                if (std::filesystem::exists(test_path)) {
                    gem_objects_path = test_path;
                    std::cout << "Found i915_gem_objects at: " << gem_objects_path << std::endl;
                    break;
                }
            }
        }
    } catch (const std::filesystem::filesystem_error& e) {
        std::cerr << "Warning: Cannot access /sys/kernel/debug/dri: " << e.what() << std::endl;
        gem_objects_path.clear();
    }
}

double IntelGpuMonitor::getGpuCoreUsage()
{
    std::string act_freq_path = gpu_dev_path + "/gt_act_freq_mhz";
    std::string max_freq_path = gpu_dev_path + "/gt_max_freq_mhz";
    std::ifstream act_file(act_freq_path);
    std::ifstream max_file(max_freq_path);

    double act_freq = 0;
    double max_freq = 0;
    if (act_file.is_open()) act_file >> act_freq;
    if (max_file.is_open()) max_file >> max_freq;

    return (max_freq > 0) ? (act_freq / max_freq * 100) : 0;
}


unsigned long long IntelGpuMonitor::getAvailableSystemMemory()
{
    std::ifstream meminfo("/proc/meminfo");
    if (!meminfo.is_open()) {
        return 0;
    }

    std::string line;
    while (std::getline(meminfo, line)) {
        if (line.find("MemAvailable:") != std::string::npos) {
            // 提取数值（单位：kB）
            size_t pos = line.find_first_of("0123456789");
            if (pos != std::string::npos) {
                std::string num_str = line.substr(pos);
                // 将 kB 转换为 bytes（乘以1024）
                return std::stoull(num_str) * 1024;
            }
        }
    }
    return 0;
}

double IntelGpuMonitor::getGpuMemUsage()
{
    // 检查缓存是否有效
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update_time).count();
    if (elapsed < CACHE_TIMEOUT_MS) {
        return cached_mem_usage;
    }

    // 如果没有找到gem_objects路径，返回缓存值
    if (gem_objects_path.empty()) {
        return cached_mem_usage;
    }

    // 直接读取文件内容
    std::ifstream file(gem_objects_path);
    if (!file.is_open()) {
        return cached_mem_usage;
    }

    std::string line;
    unsigned long long used_mem = 0;

    // 读取第一行获取已用内存
    if (std::getline(file, line)) {
        size_t pos = line.find("bytes");
        if (pos != std::string::npos) {
            std::string num_str = line.substr(0, pos);
            pos = num_str.find_last_of(",");
            if (pos != std::string::npos) {
                num_str = num_str.substr(pos + 1);
                try {
                    used_mem = std::stoull(num_str);
                } catch (const std::exception&) {
                    used_mem = 0;
                }
            }
        }
    }

    // 获取系统可用物理内存
    unsigned long long available_mem = getAvailableSystemMemory();
    
    // 如果可用内存为0，返回缓存的值避免除以0错误
    if (available_mem == 0) {
        return cached_mem_usage;
    }
    
    // 计算使用百分比并更新缓存
    cached_mem_usage = (static_cast<double>(used_mem) / static_cast<double>(available_mem)) * 100.0;
    std::cout<<"used_mem:"<<used_mem<<"bytes, available_mem:"<<available_mem<<"bytes."<<std::endl;
    last_update_time = now;

    return cached_mem_usage;
}